package com.hsyg.netty.server;

import com.hsyg.netty.server.handler.ServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 服务端开发
 */
public class Server {
  /**
   * 主方法
   *
   * @param args
   */
  public static void main(String[] args) {
    //端口号
    int port = 8888;

    if (null != args && args.length > 0) {
      try {
        port = Integer.valueOf(args[0]);

      } catch (Exception e) {
        e.printStackTrace();
      }

    }

    //绑定端口并启动服务
    new Server().bind(port);
  }

  /**
   * 主要服务
   *
   * @param port
   */
  private void bind(int port) {
    //配置服务端的nio线程组；
    //一个用于服务端接受客户端的连接；一个用于记录SocketChannel的网络对接
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workGroup = new NioEventLoopGroup();

    try {
      //服务端辅助启动类，用以降低服务端的开发复杂度
      //ServerBootstrap netty用于启动nio服务端的辅助启动类，目的是降低服务端的开发复杂度
      ServerBootstrap bootstrap = new ServerBootstrap();
      bootstrap
        .group(bossGroup, workGroup)
        //实例化ServerSocketChannel
        .channel(NioServerSocketChannel.class)
        //设置ServerSocketChannel的TCP参数
        .option(ChannelOption.SO_BACKLOG, 1024)//本质就是一个负责处理网络时间的职责链，负责管理和执行ChannelHandler
        //绑定i/0时间的处理类
        .childHandler(new ChildChannelHandler());

      //绑定端口，同步等待成功 ChannelFuture：代表异步I/O的结果
      //用于异步操作的通知回调
      ChannelFuture future = bootstrap.bind(port).sync();

      //等待服务端监听端口关闭
      //等待服务端链路关闭后main函数才能推出
      future.channel().closeFuture().sync();
    } catch (Exception e) {
      System.out.println("netty 服务端启动异常");
      e.printStackTrace();

    } finally {
      //优雅退出， 释放线程池资源
      workGroup.shutdownGracefully();
      bossGroup.shutdownGracefully();
    }

  }

  /**
   * 主要用于处理网路i/o事件
   */
  private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
      //handler
      ch.pipeline().addLast(new ServerHandler());
    }

  }

}
